package Client;
import Good.Good;
import Ticket.Ticket;
import java.awt.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Objects;

import DES.*;
import RSA.*;

import Message.Message;

public class Client {
    Boolean flag=false;
    public String pk;
    public String p;
    public String text;
    Socket server=null;
    //String IP_AS="localhost";
    String IP_AS="172.20.10.3";
    int Port_AS=1000;
    int Port_TGS=1001;
    int Port_V=1002;
    //String IP_TGS="localhost";
    String IP_TGS="172.20.10.3";
    //String IP_V="localhost";
    String IP_V="172.20.10.3";
    int port=1234;
    String type;
    DataInputStream reader;
    DataOutputStream writer;
    String ID="dzj";
    String password="12345";
    String RSA_key;
    public ArrayList<Good> goods=new ArrayList<Good>();
    int price=0;
    int charge=0;
    String key_dt="";
    public String key_dv="";
    public ArrayList<Good> shopping=new ArrayList<Good>();
    public HashMap<String,Good> history= new HashMap<String,Good>();
    public ArrayList<String> usr=new ArrayList<String>();

    public Message process(Message m)
    {
        Message newm=null;
        Ticket t=null;
        switch (Integer.parseInt(m.getTag()))
        {
            //登陆失败报文
            //认证失败报文
            //操作失败报文
            case 20:
                flag=true;
                break;
            case 30010:
                history.put(m.getRedu(), toGood(m.getContent()));
                break;
            case 31003:
                history.put(m.getRedu(), toGood(m.getContent()));
                usr.add(toGood(m.getContent()).getURL());
                break;
            case 0:
                break;
                //接收到来自AS登陆成功的报文
            case 4:
                key_dt=m.getRedu();
                try {
                    newm=new Message("00005",this.ID,"00002",120,m.getContent(),
                            RSA.encrypt(new Ticket(this.ID,"00002",5,"localhost"," ").toStr(),key_dt));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //
                //
                //
                break;
            //注册成功报文
            case 5:
                break;
                //接收到TGS认证成功的报文
            case 10:
                key_dt=m.getRedu();
                try {
                    newm=new Message("00011",this.ID,"00002",120,m.getContent(),
                            RSA.encrypt(new Ticket(this.ID,"00002",5,"localhost"," ").toStr(),key_dt));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case 12:
                key_dv=m.getRedu();
                try {
                    newm=new Message("00013",this.ID,"00003",5,m.getContent(),
                            RSA.encrypt(new Ticket(this.ID,"00003",5,"localhost",this.password).toStr(),key_dv));
                    //System.out.println(RSA.encrypt(new Ticket(this.ID,"00003",5,"localhost",this.password).toStr(),key_dv));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case 6:
                key_dv=m.getRedu();
                try {
                    newm=new Message("00007",this.ID,"00003",5,m.getContent(),
                            RSA.encrypt(new Ticket(this.ID,"00003",5,"localhost",this.password).toStr(),key_dv));
                    //System.out.println(RSA.encrypt(new Ticket(this.ID,"00003",5,"localhost",this.password).toStr(),key_dv));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case 8:
                this.charge=Integer.parseInt(m.getContent());
                flag=true;
                System.out.println(charge);
                break;
            case 30005:
                Good g=toGood(m.getContent());
                this.goods.add(g);
                break;
            case 30003:
                charge= Integer.parseInt(m.getContent());
                break;
            case 30001:
                this.price=Integer.parseInt(m.getContent());
                this.charge-=this.price;
                break;
            case 30006:
            case 31004:
            case 30007:
                g=toGood(m.getContent());
                goods.add(g);
                break;
            case 30002:
                break;

        }
        return newm;
    }
    public void send(String m)
    {
        try {
            if(flag==true) {
                pk = RSA.encrypt(m, key_dv);
                pk = DES.encrypt(pk, DES.getSecretKey(ID));
                p = m;
            }
            writer.writeUTF(m);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public String recv()
    {
        try {

            return reader.readUTF();
        } catch (IOException e) {
            return "";
        }
    }
    public static void openORL(String url)
    {
        try {
            URI u1 = null;
            try {
                u1 = new URI(url);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            try {
                Desktop.getDesktop().browse(u1);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    String recv(String key)
    {
//        Calendar cal=Calendar.getInstance();
//        key=key+ cal.getTime();
        String s=recv();
        try {
            s=DES.decrypt(s,DES.getSecretKey(key));
            return s;
        } catch (Exception e) {
            return null;
        }
    }
    void send(String s,String key)
    {
//        Calendar cal=Calendar.getInstance();
//        key=key+ cal.getTime();
        try {
            send(DES.decrypt(s,DES.getSecretKey(key)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //与服务器连接
    void conn(String IP,int port)
    {
        try {
            this.server=new Socket(IP,port);
            this.reader = new DataInputStream(this.server.getInputStream());
            this.writer = new DataOutputStream(this.server.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    void close_stream()
    {
        try {
            this.server.shutdownOutput();
            this.server.shutdownInput();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public Message toMessage(String s)
    {
        String []a=s.split("\\|");
        Message m=new Message(a[Message.pos.tag.ordinal()],
                a[Message.pos.ID_src.ordinal()],
                a[Message.pos.ID_dst.ordinal()],
                Integer.parseInt(a[Message.pos.lifetime.ordinal()]),
                a[Message.pos.content.ordinal()],
                a[Message.pos.redu.ordinal()]
        );
        String time=a[Message.pos.TS.ordinal()];
        int day=Integer.parseInt(time.substring(0,2));
        int hour=Integer.parseInt(time.substring(2,4));
        int minute=Integer.parseInt(time.substring(4,6));
        Calendar c=Calendar.getInstance();
        c.set(Calendar.HOUR,hour);
        c.set(Calendar.MINUTE,minute);
        c.set(Calendar.DATE,day);
        m.setTS(c);
        return m;
    }
    public Ticket toTicket(String s)
    {
        String []a=s.split("-");
        Ticket m=new Ticket(a[Ticket.pos.ID_src.ordinal()],
                a[Ticket.pos.ID_dst.ordinal()],
                Integer.parseInt(a[Ticket.pos.lifetime.ordinal()]),
                a[Ticket.pos.ADC.ordinal()],
                a[Ticket.pos.key.ordinal()]
        );
        String time=a[Ticket.pos.TS.ordinal()];
        int day=Integer.parseInt(time.substring(0,2));
        int hour=Integer.parseInt(time.substring(2,4));
        int minute=Integer.parseInt(time.substring(4,6));
        Calendar c=Calendar.getInstance();
        c.set(Calendar.HOUR,hour);
        c.set(Calendar.MINUTE,minute);
        c.set(Calendar.DATE,day);
        m.setTS(c);
        return m;
    }
    //获取账号密码
    public void get(String ID, String psw)
    {
        this.ID=ID;
        this.password=psw;
    }

    public Message Check()
    {
        Message m=new Message("10005",this.ID,"00003",5,"check"," ");
        send(m.toStr());
        return toMessage(recv());
    }

    public Message GetHistory(int count)
    {
        Message m=new Message("10010",this.ID,"00003",5," ",String.valueOf(count));
        send(m.toStr());
        return toMessage(recv());
    }

    Good toGood(String s)
    {
        String []a=s.split("-");
        return new Good(a[0],a[1],Integer.parseInt(a[2]),Integer.parseInt(a[3]),a[4],a[5]);
        //return g;
    }

    public Message GetByName(String name)
    {
        Message m=new Message("10007",this.ID,"00003",5,name," ");
        send(m.toStr());
        return toMessage(recv());
    }
    public Message GetByType(String type)
    {
        Message m=new Message("10006",this.ID,"00003",5,type," ");
        send(m.toStr());
        return toMessage(recv());
    }
    public Message Buy(Good g)
    {
        Message m=new Message("10001",this.ID,"10003",5,g.toStr()," ");
        send(m.toStr());
        return toMessage(recv());
    }
    public Message Charge(int num)
    {
        Message m=new Message("10003",this.ID,"00003",5,String.valueOf(num)," ");
        send(m.toStr());
        return toMessage(recv());
    }

    public Message Change(String psw)
    {
        Message m=new Message("10004",this.ID,"10003",5,psw," ");
        send(m.toStr());
        return toMessage(recv());
    }

    public Message Ret(String b_ID)
    {
        Message m=new Message("10002",this.ID,"00003",5,b_ID," ");
        send(m.toStr());
        return toMessage(recv());
    }

    public Message CheckGood(int i)
    {
        Message m=new Message("20004",this.ID,"10003",5," ",String.valueOf(i));
        send(m.toStr());
        return toMessage(recv());
    }

    public Message Add(Good g)
    {
        Message m=new Message("20001",this.ID,"10003",5,g.toStr()," ");
        send(m.toStr());
        return toMessage(recv());
    }

    public Message AddGood(String p_ID, int p_num)
    {
        Message m=new Message("20002",this.ID,"10003",5,p_ID,String.valueOf(p_num));
        send(m.toStr());
        return toMessage(recv());
    }

    public Message CheckHistory(int i)
    {
        Message m=new Message("20003",this.ID,"10003",5," ",String.valueOf(i));
        send(m.toStr());
        return toMessage(recv());
    }

    Boolean check()
    {
        return true;
    }
    //开始验证登录
    public void start()
    {
        flag=false;
        Message m;
        Ticket t;
        String s = null;
        this.conn(this.IP_AS,this.Port_AS);
        m=new Message("00001",this.ID,"00001",120," "," ");
        send(m.toStr());
        try {
            s=recv(this.ID);
            System.out.println(s);
            //DES.getSecretKey(this.ID);
            m=toMessage(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        text=s+"\nrecv from AS: "+m.toStr();
        System.out.println(text);
        close();
        //登录失败结束
        if(Objects.equals(m.getTag(), "00000"))
        {
            return;
        }
        m=process(m);
        this.conn(this.IP_TGS,this.Port_TGS);
        send(m.toStr());
        s=recv(this.ID);
        m=toMessage(s);
        text+=s+"\nrecv from TGS: "+m.toStr();
        System.out.println(text);
        m=process(m);
        System.out.println("send to V: "+m.toStr());
        close();

        //
        conn(IP_V,Port_V);
        send(m.toStr());
        s=recv();
        m=toMessage(s);
        text+=s+"\nrecv from V: "+m.toStr();
        System.out.println(text);
        process(m);


    }

    public void rigister()
    {
        flag=false;
        Message m;
        Ticket t;
        String s = null;
        this.conn(this.IP_AS,this.Port_AS);
        m=new Message("00002",this.ID,"00001",120," "," ");
        send(m.toStr());
        try {
            s=recv(this.ID);
            System.out.println(s);
            //DES.getSecretKey(this.ID);
            m=toMessage(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        text=s+"\nrecv from AS: "+m.toStr();
        System.out.println(text);

        close();

        //登录失败结束
        if(Objects.equals(m.getTag(), "00000"))
        {
            return;
        }
        m=process(m);
        this.conn(this.IP_TGS,this.Port_TGS);
        send(m.toStr());
        s=recv(this.ID);
        m=toMessage(s);
        text=s+"\nrecv from TGS: "+m.toStr();
        System.out.println(text);

        m=process(m);
        System.out.println("send to V: "+m.toStr());
        close();

        //
        conn(IP_V,Port_V);
        send(m.toStr());
        s=recv();
        m=toMessage(s);
        text=s+"\nrecv from V: "+m.toStr();
        System.out.println(text);
    }

    //关闭socket连接
    public void close()
    {
        try {
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean getFlag() {
        return flag;
    }

    public int getCharge() {
        return charge;
    }
}
